{$R-}                             {Range checking off}
{$B+}                             {Boolean short circuiting off}
{$S-}                             {Stack checking off}
{$I-}                             {I/O checking off}
{$V-}                             { disable string parameter type checking - faster }


UNIT RUNPART1;

INTERFACE

USES
  Crt,
  Dos,
  Graph3,
  Turbo3;

  {****************************************************}
  {                     Constants                      }
  {****************************************************}

  {$IFDEF NormalVersion}

CONST                             {CONST for Normal Version}
  {Locations: each noun and creature has a location at any given}
  {time, stored as an integer. This should correspond to the}
  {range from (Nowhere..last_creature), broken down as follows:}
  {       0:  noun has been destroyed or}
  {           noun never existed - undefined}
  {       1:  noun is being carried by player}
  {           (and moves with him/her/it)}
  {    1000:  noun is being worn by player}
  {           (and moves with him/her/it)}
  {  2..199:  noun is located in a room within the}
  {           adventure game map.}
  {200..299:  noun is located inside another noun}
  {300..399:  noun is being carried by a creature}

  {Creatures may only be located in the range  0..199, since}
  {they cannot be inside a noun. They also cannot be carried}
  {by the player, so the value 1 is also invalid.}
  {The player's location must be a room number (2..199)}
  Player = 1;
  Wearing = 1000;
  First_Room = 2;
  Last_Room = 199;
  First_noun = 200;
  Last_noun = 299;
  First_creature = 300;
  Last_Creature = 399;
  First_Message = 1;
  Last_Message = 250;
  Num_Verbs = 105;
  {number of verbs understood by program}
  Num_Dirs = 13;                  {13 directions: 10 dirs, plus}
  {'ENTER' and 'EXIT' and 'special' direction}
  MaxSizeCommand = 30;            {max. number of data items in SpecialCMD}
  MaxCommand = 400;               {max. number of SpecialCMDs}
  MaxCounter = 25;                {max. number of counters}
  MaxVariable = 25;               {max. number of variables}
  MaxQuestion = 25;               {max. number of questions and answers}
  MaxFlag = 255;                  {max. number of flags}
  MaxDupsInRoom = 5;              {max. number of duplicate nouns with same name in room}

  {$ELSE}

CONST                             {CONST for "BIG" Version}
  {Locations: each noun and creature has a location at any given}
  {time, stored as an integer. This should correspond to the}
  {range from (Nowhere..last_creature), broken down as follows:}
  {       0:  noun has been destroyed or}
  {           noun never existed - undefined}
  {       1:  noun is being carried by player}
  {           (and moves with him/her/it)}
  {    1000:  noun is being worn by player}
  {           (and moves with him/her/it)}
  {  2..299:  noun is located in a room within the}
  {           adventure game map.}
  {300..499:  noun is located inside another noun}
  {500..699:  noun is being carried by a creature}

  {Creatures may only be located in the range  0..299, since}
  {they cannot be inside a noun. They also cannot be carried}
  {by the player, so the value 1 is also invalid.}
  {The player's location must be a room number (2..299)}
  Player = 1;
  Wearing = 1000;
  First_Room = 2;
  Last_Room = 299;
  First_noun = 300;
  Last_noun = 499;
  First_creature = 500;
  Last_Creature = 699;
  First_Message = 1;
  Last_Message = 600;
  Num_Verbs = 105;
  {number of verbs understood by program}
  Num_Dirs = 13;                  {13 directions: 10 dirs, plus}
  {'ENTER' and 'EXIT' and 'special' direction}
  MaxSizeCommand = 30;            {max. number of data items in SpecialCMD}
  MaxCommand = 900;               {max. number of SpecialCMDs}
  MaxCounter = 50;                {max. number of counters}
  MaxVariable = 50;               {max. number of variables}
  MaxQuestion = 25;               {max. number of questions and answers}
  MaxFlag = 255;                  {max. number of flags}
  MaxDupsInRoom = 5;              {max. number of duplicate nouns with same name in room}
  {$ENDIF}

  MoreLimit = 21;                 {number of lines before "More" message pause}
  Mono = 7;                       {Monochrome display mode}
  Nowhere = 0;                    {Room where noun does't exist (yet)}
  Max_Weight = 100;               {Max total weight player can carry}
  Max_Size = 100;                 {Max total size player can carry}
  
  (******************************************************)
  (*                     Types                          *)
  (******************************************************)

TYPE
  String30 = String[30];
  String255 = String[255];
  CreatureType = (Thing {default creature/animal/beast} ,
                  Woman {changes pronouns to "SHE" and "HER"} ,
                  Man {changes pronouns to "HE" and "HIM"} );
  SingularOrPlural = (Singular, Plural);
  {used to select "IS" or "ARE" and "IT" or "THEM" for nouns}
  Direction = (NORTH, SOUTH, EAST, WEST, northeast, northwest, southeast,
               southwest, up, down, enter, Exit);
  {possible directions leading from each room}
  s = String[80];                 {sentences, lines of text}
  names = String[22];             {room, noun names}
  words = names;                  {words in player input}
  descr_files = FILE OF s;

  descr = RECORD
            start : Integer;      {position in descr_file}
            len : Integer;        {number of lines}
          END;

  Dups = RECORD
           num : Integer;         {number of duplicate noun/creature in room}
           adj : words;           {adjective}
           name : words;          {proper name -- NOT synonym}
         END;

  (****************************************************)
  (*            Room Data Structure                   *)
  (****************************************************)

  RoomPointer = ^rooms;

  rooms = RECORD
            name : String30;
            Replaced_Word : words; {In this room only -- Replace this verb}
            Replacing_Words : s;  {with these verbs}
            Path : ARRAY[Direction] OF Integer; {exits from room -- changed by DRM}
            special : Integer;
            has_seen : Boolean;   {player has seen room}
            key : Integer;        {noun that activates special}
            locked_door : Boolean;
            nouns_inside : Integer; {count of nouns in this room}
            points : Integer;     {reward for getting here}
            light : Integer;
            {what noun lights this room?}
            {0 means no light needed 1 means any light}
            game_end : Boolean;
            game_win : Boolean;
            player_dead : Boolean; {does the player die when entering room?}
          END;                    {record}

  roomlists = ARRAY[First_Room..Last_Room] OF RoomPointer;

  (********************************************************)
  (*              Nouns data structure                    *)
  (********************************************************)

  NounPointer = ^nouns;

  nouns = RECORD
            name : names;
            short : s;            {short one-line description}
            adj : names;          {adjective - 'NO_ADJ' if none}
            SingOrPlur : SingularOrPlural; {used to select "IS" or "ARE"}
            position : names;     {i.e., 'behind the door'-- Added by DRM}
            SomethingPositionedNearThisNoun : Boolean;
            {i.e.,something is 'behind' this noun'}
            ThisNounPositionedNearNounNumber : Integer;
            {i.e.,number of noun this noun is 'behind'}
            Has_Synonyms : Boolean; {Are there Synonyms for this noun's name}
            synonyms : s;         {List of Synonyms for this noun -- if any}
            location : Integer;   {where is it? 1=player}
            weight : Integer;     {how heavy?}
            size : Integer;       {how bulky?}
            key : Integer;        {item # that unlocks it}
            pushable : Boolean;   {'specials' and 'PUSH_DESCR'}
            pullable : Boolean;   {'specials' and 'PULL_DESCR'}
            turnable : Boolean;   {'specials' and 'TURN_DESCR'}
            playable : Boolean;   {'specials' and 'PLAY_DESCR'}
            readable : Boolean;   {if true, there should be}
            {TEXT to match in the data file}
            on : Boolean;         {if not on, then off}
            closable : Boolean;   {can player open/close it?}
            open : Boolean;       {can things be put in it?}
            lockable : Boolean;   {can it be locked and unlocked?}
            locked : Boolean;     {if so, is it locked now?}
            edible : Boolean;     {can it be eaten?}
            wearable : Boolean;   {can it be worn?}
            drinkable : Boolean;  {can it be drunk?}
            poisonous : Boolean;  {if it's eaten or drunk}
            movable : Boolean;    {can it be lifted at all?}
            is_light : Boolean;   {does it work as a light?}
            can_shoot : Boolean;  {can it shoot ?}
            num_shots : Integer;  {number of bullets}
            points : Integer;     {what's it worth?}
            nouns_inside : Integer; {count of other nouns inside this noun}
            game_win : Boolean;   {does player win when}
            {s/he gets this noun?}
          END;                    {record}

  nounlists = ARRAY[First_noun..Last_noun] OF NounPointer;

  {***************************************************}
  {            Creatures data structure               }
  {***************************************************}

  CreaturePointer = ^creatures;   {to save DATA segment space}

  creatures = RECORD
                name : names;
                short : s;        {short one-line description}
                adj : names;      {adjective - 'NO_ADJ' if none}
                Has_Synonyms : Boolean; {Are there Synonyms for this creature's name}
                synonyms : s;     {List of Synonyms for this creature -- if any}
                groupmember : Boolean; {is it a member of the group?}
                location : Integer;
                weapon : Integer; {item # that kills it}
                hostile : Boolean; {is s/he/it hostile?}
                points : Integer; {what's it worth?}
                nouns_inside : Integer; {count of nouns creature is carrying}
                counter : Integer; {how many times has the}
                {player been nasty to it?}
                threshhold : Integer; {how many will it take?}
                timethresh : Integer; {how long before it attacks?}
                timecounter : Integer; {how many turns has}
                {the player been here?}
                gender : CreatureType; {Thing(default), Woman, Man}
              END;                {record}

  creaturelists = ARRAY[First_creature..Last_Creature] OF CreaturePointer;

  {***********************************************}
  {        Custom Command Data Structure          }
  {***********************************************}

  CommandPointer = ^Command;

  Command = RECORD
              VerbNum : Integer;  {verb number}
              VerbCMD : words;    {verb}
              NounCMD : words;    {noun}
              ObjectCMD : words;  {object}
              Data : ARRAY[1..MaxSizeCommand] OF Integer;
            END;                  {of record}

  CommandList = ARRAY[1..MaxCommand] OF CommandPointer;

  {***********************************************}
  {   S P E C I A L  C O M M A N D  T O K E N S   }
  {***********************************************}

  {*******  CONDITION TOKENS ********}
  Token = (
    AtLocation,                   {Player is located at room loc#}
    AtLocationGT,                 {In room greater than loc#}
    AtLocationLT,                 {In room less than loc#}
    FirstVisitToRoom,             {Player is in current room for first time}
    NewLife,                      {Player is just starting game or has just been resurrected}
    IsCarryingSomething,          {Player is carrying something}
    IsCarryingNothing,            {Player is carrying nothing}
    IsWearingSomething,           {Player is wearing something}
    IsCarryingTreasure,           {Player is carrying at least one treasure worth >= PTS}
    IsWearingNothing,             {Player is wearing nothing}
    LoadWeightEquals,             {Load weighs equals num#}
    LoadWeightGT,                 {Load weighs more than num#}
    LoadWeightLT,                 {Load weighs less than num#}
    Present,                      {ITEM is in room, carried or worn}
    IsWearing,                    {ITEM is being worn}
    IsCarrying,                   {ITEM is being carried}
    IsNowhere,                    {ITEM is located NOWHERE (room 0)}
    IsSomewhere,                  {ITEM is located somewhere}
    InRoom,                       {ITEM is located in current room}
    IsLocated,                    {ITEM# is located in room loc#}
    Together,                     {ITEM# and ITEM# are in same room}
    IsON,                         {ITEM is ON}
    IsOFF,                        {ITEM is OFF}
    IsGroupMember,                {ITEM is member of the group}
    IsOpen,                       {ITEM is Open}
    IsClosed,                     {ITEM is Closed}
    IsLocked,                     {ITEM is Locked}
    IsUnLocked,                   {ITEM is UnLocked}
    IsEdible,                     {ITEM is Edible}
    IsDrinkable,                  {ITEM is Drinkable}
    IsPoisonous,                  {ITEM is Poisonous}
    IsMovable,                    {ITEM is Movable}
    NOUNPresent,                  {NOUN is in room, carried or worn}
    NOUNIsWearing,                {NOUN is being worn}
    NOUNIsCarrying,               {NOUN is being carried}
    NOUNIsNowhere,                {NOUN ITEM is located NOWHERE (room 0)}
    NOUNIsSomewhere,              {NOUN ITEM is located somewhere}
    NOUNInRoom,                   {NOUN ITEM is located in current room}
    NOUNIsLocated,                {NOUN ITEM is located in room loc#}
    NOUNIsON,                     {NOUN ITEM is ON}
    NOUNIsOFF,                    {NOUN ITEM is OFF}
    NOUNIsOpen,                   {NOUN ITEM is Open}
    NOUNIsClosed,                 {NOUN ITEM is Closed}
    NOUNIsLocked,                 {NOUN ITEM is Locked}
    NOUNIsUnLocked,               {NOUN ITEM is UnLocked}
    NOUNIsEdible,                 {NOUN ITEM is Edible}
    NOUNIsDrinkable,              {NOUN ITEM is Drinkable}
    NOUNIsPoisonous,              {NOUN ITEM is Poisonous}
    NOUNIsMovable,                {NOUN ITEM is Movable}
    NOUNpointsEquals,             {NOUN points equal num#}
    NOUNpointsGT,                 {NOUN points are greater than num#}
    NOUNpointsLT,                 {NOUN points are less than num#}
    NOUNweightEquals,             {NOUN weight equals num#}
    NOUNweightGT,                 {NOUN weight is greater than num#}
    NOUNweightLT,                 {NOUN weight is less than num#}
    LightPresent,                 {Room has necessary light}
    RoomNeedsLight,               {Room needs a light}
    FlagON,                       {Flag# is ON}
    FlagOFF,                      {Flag# is OFF}
    ScoreEquals,                  {current score is equal to num}
    ScoreGT,                      {score is greater than num}
    ScoreLT,                      {score is less than num}
    NumberEquals,                 {current input number is equal to num}
    NumberGT,                     {input number is greater than num}
    NumberLT,                     {input number is less than num}
    AnswerIsCorrect,              {last answer is correct}
    AnswerIsWrong,                {last answer is wrong}
    TurnsEquals,                  {current Turns is equal to num}
    TurnsGT,                      {Turns is greater than num}
    TurnsLT,                      {Turns is less than num}
    CounterEquals,                {Counter # is equal to num}
    CounterGT,                    {Counter # is greater than num}
    CounterLT,                    {Counter # is less than num}
    VariableEquals,               {Variable # is equal to num}
    VariableGT,                   {Variable # is greater than num}
    VariableLT,                   {Variable # is less than num}
    CompareVariables,             {TRUE if V1 < V2 }
    VariableChance,               {TRUE if V < Random(1..N)}
    NamePresent,                  {TRUE if Name being addressed is at location}
    NameIsNumber,                 {TRUE if Name being addressed is Noun or Creature Number num}
    NOUNIsNumber,                 {TRUE if NOUN is Number num}
    ObjectIsNumber,               {TRUE if Object is Number num}
    SomethingInside,              {TRUE if there is something inside of object num}
    Chance,                       {Odds are percent, i.e. 10 %}
    PromptForYES,                 {Prompts for Y or N -- Ok if Yes}
    PromptForNO,                  {Prompts for Y or N -- Ok if No}
    VerbIsDirection,              {Verb is movement or direction}
    NounIsCreature,               {TRUE if noun is a creature}
    ObjectIsCreature,             {TRUE if object is a creature}
    ObjectPresent,                {TRUE if object is present in room}
    LogicalNOT,                   {Logical NOT of current condition}
    LogicalOR,                    {Logical OR of conditions -- MUST be last condition}
    {in CMD file token in indicated as "OR"}

    {******* ACTIONS TOKENS *********}

    GoToRoom,                     {Send player to loc#}
    GoToRandomRoom,               {Randomly pick room >= num1 and <= num2 and move player}
    MakeVarRoomNum,               {Var# -- will make Var# equal current room number}
    MakeVarNounNum,               {Var# -- will make Var# equal current noun number}
    MakeVarObjectNum,             {Var# -- will make Var# equal object room number}
    GoToVariableRoom,             {Var# -- will send player to room number Var#}
    SendToVariableRoom,           {Item# Var# -- will send Item# to room number Var#}
    GetVariableIt,                {Var# -- will get Var# item for player}
    PrintVariableMessage,         {Var# -- will print message number Var#}
    GetIt,                        {ITEM# is now being carried}
    WearIt,                       {ITEM# is now being worn}
    DropIt,                       {Drops ITEM# into current room}
    RemoveIt,                     {Removes ITEM and drops into room}
    GetNOUN,                      {NOUN is now being carried}
    WearNOUN,                     {NOUN is now being worn}
    DropNOUN,                     {Drops NOUN into current room}
    RemoveNOUN,                   {Removes NOUN and drops into room}
    DropEverything,               {Drop all items being carried}
    RemoveEverything,             {Remove all items being worn}
    KillPlayer,                   {Makes player dead}
    PutInCurrentRoom,             {Put ITEM# in current room}
    SendToRoom,                   {Put ITEM# in room loc#}
    PutNOUNInCurrentRoom,         {Put NOUN in current room}
    SendNOUNToRoom,               {Put NOUN in room loc#}
    SendAllToRoom,                {Send all carried ITEMs to loc#}
    SendTreasuresToRoom,          {Send all carried ITEMs whose points > pts# to loc#}
    RelocateAll,                  {Move all items at loc1 to loc2}
    Destroy,                      {ITEM# is now NOWHERE (room 0)}
    DestroyNOUN,                  {NOUN is now NOWHERE (room 0)}
    SwapLocations,                {swap locations of ITEM1 & ITEM2}
    SendToItem,                   {Put ITEM1 in location of ITEM2}
    SendNOUNToItem,               {Put NOUN in location of ITEM}
    AddToGroup,                   {Add ITEM# to group}
    RemoveFromGroup,              {Remove ITEM# from group}
    MoveTheGroup,                 {Move group to room ITEM#}
    ReDirectTo,                   {Re-Direct command to different VERB-NOUN-OBJECT}
    RandomMessage,                {Select message between Num1 and Num2 and print it}
    ShowContents,                 {Display object inside of num -- if any}
    OpenIt,                       {ITEM# is now open}
    CloseIt,                      {ITEM# is now closed}
    LockIt,                       {ITEM# is now locked}
    UnlockIt,                     {ITEM# is now unlocked}
    OpenNOUN,                     {NOUN is now open}
    CloseNOUN,                    {NOUN is now closed}
    LockNOUN,                     {NOUN is now locked}
    UnlockNOUN,                   {NOUN is now unlocked}
    ShowScore,                    {Show current SCORE}
    PlusScore,                    {Add num to current SCORE}
    MinusScore,                   {Subtract num from current SCORE}
    ShowInventory,                {Show current INVENTORY}
    WaitForReturn,                {Prints 'Hit RETURN' message}
    TimePasses,                   {Show 'Time passes...' message}
    xDelay,                       {Delay for num seconds}
    CLEARSCREEN,                  {Clears screen}
    DescribeThing,                {Describe thing num (whatever)}
    LookAtRoom,                   {Cause a VERBOSE look at room}
    PrintMessage,                 {Prints message num}
    BlankLine,                    {Prints blank line}
    Tone,                         {makes a sound at H hertz for M milliseconds}
    GetNumberInput,               {Get number as input}
    AskQuestion,                  {ask question and get answer}
    ChangePassageway,             {opens or closes a passage between rooms}
    TurnFlagON,                   {Turn Flag# ON}
    TurnFlagOFF,                  {Turn Flag# OFF}
    ToggleFlag,                   {Toggle Flag#}
    TurnCounterON,                {Turn counter# ON -- sets to 1}
    TurnCounterOFF,               {Turn counter# OFF -- sets to 0}
    SetVariableTo,                {Set Variable var# to num#}
    AddToVariable,                {Add num# to Variable var#}
    SubtractFromVariable,         {Subtract num# from Variable #}
    AddVariables,                 {Add V2 to V1 and store answer in V1}
    SubtractVariables,            {Subtract V2 from V1 and store answer in V1}
    RandomVariable,               {Set Var# to Random number [1..Num]}
    NounToVariable,               {Convert Noun to Variable #}
    ObjectToVariable,             {Convert Object to Variable #}
    WinGame,                      {Player wins game at end of turn}
    EndGame,                      {game ends at end of turn}
    QuitThisCMD,                  {Quit evaluating this CMD}
    QuitAllCMDs,                  {Finished with all special CMDs}
    DoneWithTurn);                {All Done this turn -- get next turn's input next}
  {last token}

  (*************************************************)
  (*        Verbs and Global synonym lists         *)
  (*************************************************)

  verblists = ARRAY[0..Num_Verbs] OF words; {0 is for 'ANY'}
  Synlists = ARRAY[0..Num_Verbs] OF s; {whole line of several synonyms}

  (******************************************************)
  (*                 Global Variables                   *)
  (******************************************************)

VAR
  SpecialCMD : CommandList;       {stores pointers to custom commands}
  counter : ARRAY[0..MaxCounter] OF Integer;
  Variable : ARRAY[0..MaxVariable] OF Integer;
  Question, Answer : ARRAY[0..MaxQuestion] OF s;
  Flag : ARRAY[0..MaxFlag] OF Boolean;
  P : ARRAY[Token] OF Integer;
  DuplicatesInRoom : ARRAY[1..MaxDupsInRoom] OF Dups;
  Cap_Subject_IT, Subject_IT, Object_IT, Snarls, Screeches : ARRAY[CreatureType] OF words;
  IsOrAre, ItOrThem : ARRAY[SingularOrPlural] OF words;
  StartingIndex : ARRAY[0..Last_Creature] OF Integer; {used for index}
  EndingIndex : ARRAY[0..Last_Creature] OF Integer; {sequential searches}
  DoNormalCMD, Skip_A_Line : Boolean;
  ScoreAdjustment, Treasure_Room, Maximum_Score, NumberInput, NumberInRoom : Integer;
  Room : roomlists;
  Current_room : Integer;         {what room is player "now" in}
  Previous_room : Integer;        {the room the player was in - last turn}
  Starting_room : Integer;        {the room the player starts in}
  Current_Life : Integer;         {what life is player now playing}
  Num_turns : Integer;            {number of turns taken}
  Num_saves, num_restores : Integer; {# of times game saved/restored}
  N : nounlists;                  {array [first_noun..last_noun] of nouns}
  M : creaturelists;              {array [first_creature..last_creature] of creatures}
  V : verblists;                  {the array of verbs, used only to check input}
  SYN : Synlists;                 {verb synonyms -- whole line full of synonyms}
  Original_Verb, LastVerb : words; {verb (as entered) before any synonym substitition}
  Last_CMD, MaxRoom, MaxNoun, MaxCreature, MaxVerb : Integer;
  Any_Special_Cmds, CreatingFinalVersion, UsingFinalVersion : Boolean; {flag -- TRUE of appropriate}
  datafile : Text;
  descr_file : descr_files;
  Command_File_Name, Instruction_File_Name, Adventure_Name,
  data_file_name,
  title_file_name, descr_file_name : words;
  player_dead : Boolean;          {useful so player knows when s/he dies}
  game_won, game_end, QuestionStatus, OK_To_Display_Keys, DoingUpperCase,
  PreviousCompoundCommands, DoingCompoundCommands : Boolean;
  verbose : Boolean;              {does player want long descriptions when s/he}
  {first enters a room, or only when requested?}
  FirstVisitFlag, NewLifeFlag, ResurrectedFlag : Boolean;
  morecount : Integer;            {number of lines since last pause}
  NormalConOutPtr : Integer;
  {used to replicate the Ctrl PrtSc key in software}
  {for SCRIPT and UNSCRIPT commands}
  Items_Being_Carried : Integer;
  Items_Being_Worn, Old_Cursor : Integer;
  NormalTextColor,
  NormalTextBackground,
  HighLightTextColor,
  ReverseTextColor,
  ReverseTextBackground : Integer;
  Max_Lives,                      {max. number of lives for player}
  Resurrection_Room : Integer;

  {Pointers to descriptions on disk}
  Room_Ptr : ARRAY[First_Room..Last_Room] OF descr;
  Special_Ptr : ARRAY[First_Room..Last_Room] OF descr;
  Help_Ptr : ARRAY[First_Room..Last_Room] OF descr;
  Noun_Ptr : ARRAY[First_noun..Last_noun] OF descr;
  Play_Ptr : ARRAY[First_noun..Last_noun] OF descr;
  Turn_Ptr : ARRAY[First_noun..Last_noun] OF descr;
  Push_Ptr : ARRAY[First_noun..Last_noun] OF descr;
  Pull_Ptr : ARRAY[First_noun..Last_noun] OF descr;
  Text_Ptr : ARRAY[First_noun..Last_noun] OF descr;
  Message_Ptr : ARRAY[First_Message..Last_Message] OF descr;
  Creature_Ptr : ARRAY[First_creature..Last_Creature] OF descr;
  Intro_Ptr : descr;
  sentence, LastPart : s;         {used for player's input string}
  verb, noun, prep, object_word, noun_adj, object_adj, NameStr : words; {returned by parser}
  last_noun_used, last_adj_used : words;
  {used by parser to understand "IT" "THEM" "HIM" & "HER"}
  NounNumber, ObjectNumber, NameNum, TempNameNum : Integer;
  {determined in parser}
  Duplicate, Scripting : Boolean;
  Adjective : words;
  syntax_error : Boolean;         {flag - if parser finds a problem}
  Word_Chars : SET OF Char;
  {don't try to execute the input command}

CONST
  fmClosed = $D7B0;               { magic numbers for Turbo }
  fmInput = $D7B1;
  fmOutput = $D782;
  fmInOut = $D7B3;

  IO_Invalid = $FC;               { invalid operation eg. attempt to write }
  { to a file opened in fmInput mode       }

  LPTNames : ARRAY[0..2] OF String[4] = ('LPT1', 'LPT2', 'LPT3');

VAR
  IO : Text;

FUNCTION DoInt17(Ch : Char; LPTNo : Word) : Byte;
  { send a character to LPTNo via ROM BIOS int 17h func 0h }
  { implented as an inline "macro" for speed and the heck  }
  { of it! Bet you've seen this routine before!            }
  INLINE(
    $5A/                          {  pop     DX    ; get printer number}
    $58/                          {  pop     AX    ; get char}
    $B4/$00/                      {  mov     AH,00 ; set AH for BIOS int 17h function 0}
    $CD/$17/                      {  int     $17   ; do an int 17h}
    $86/$E0);                     {  xchg    AL,AH ; put byte result in AL}

PROCEDURE AssignLst(VAR F : Text; LPTNumber : Word);
  { like Turbo's assign, except associates Text variable with one of the LPTs }

PROCEDURE BigWindow;

PROCEDURE LittleWindow;

PROCEDURE ChangeCursor(NewSize : Integer; VAR OldSize : Integer);

FUNCTION DisplayMode : Byte;

PROCEDURE reverse;

PROCEDURE normal;

PROCEDURE highlight;

PROCEDURE RestoreCursor;

PROCEDURE Pause;

PROCEDURE EXPLAIN_Keys;

FUNCTION GetInputString : s;
  {Gets adventure input sentences -- also inputs function and direction keys}

FUNCTION Encode(textrec : s) : s;

FUNCTION Decode(textrec : s) : s;

PROCEDURE Skip_spaces(sentence : s; VAR i : Integer; l : Integer);

PROCEDURE Capitalize(VAR sentence : s);

PROCEDURE Normalize(VAR w : names);

FUNCTION Value(sentence : s) : Integer;

FUNCTION first_word(sentence : s) : words;

FUNCTION But_First(sentence : s) : s;

FUNCTION File_Exists(filename : words) : Boolean; {From the 3.0 manual,}

FUNCTION Is_Verb(w : words) : Boolean;

FUNCTION Is_Direction(w : words) : Boolean;

FUNCTION Is_Noun(w : words) : Boolean;

FUNCTION Is_Creature(w : words) : Boolean;

FUNCTION Is_Prep(w : words) : Boolean;

FUNCTION Verb_Number(w : words) : Integer;

FUNCTION location(num : Integer) : Integer;

FUNCTION Is_Visible(num : Integer) : Boolean;

FUNCTION Noun_Number(w : words) : Integer;

FUNCTION Creature_Number(w : words) : Integer;

FUNCTION name(num : Integer) : names;

FUNCTION Room_Location(num : Integer) : Integer;

FUNCTION Load_Weight : Integer;

FUNCTION Load_Size : Integer;

PROCEDURE Adjust_Count(PLACE, INCREMENT : Integer);

FUNCTION Things_Here(PLACE : Integer) : Integer;

FUNCTION Things_Adjective(num : Integer) : words;

PROCEDURE Consume(noun : words);

PROCEDURE List_Contents(loc : Integer;
                        level : Integer);

PROCEDURE List_Creatures(loc : Integer);

PROCEDURE Handle_Word_Combinations(VAR sentence : s);

PROCEDURE CheckForName(VAR sentence : s);

PROCEDURE MoveGroup(FromLoc, ToLoc : Integer);

PROCEDURE SwapWords(FromWord, ToWord : words; VAR sentence : s; LowerCase : Boolean);

PROCEDURE Describe_It(keyword : words; num : Integer);

FUNCTION LightIsHere : Boolean;

PROCEDURE Describe_scene;

PROCEDURE Describe(w : words);

PROCEDURE Drop(noun : words);
  {===========================================================================}

IMPLEMENTATION

  {===========================================================================}

TYPE
  TextBuffer = ARRAY[0..127] OF Char;

  textrec = RECORD
              Handle : Word;
              Mode : Word;
              BufSize : Word;
              Private : Word;
              BufPos : Word;
              BufEnd : Word;
              BufPtr : ^TextBuffer;
              OpenFunc : Pointer;
              InOutFunc : Pointer;
              FlushFunc : Pointer;
              CloseFunc : Pointer;
              { 16 byte user data area, I use 4 bytes }
              PrintMode : Word;   { not currently used}
              LPTNo : Word;       { LPT number in [0..2] }
              UserData : ARRAY[1..12] OF Char;
              name : ARRAY[0..79] OF Char;
              Buffer : TextBuffer;
            END;

  PROCEDURE Out_Char(Ch : Char; LPTNo : Word; VAR ErrorCode : Integer);
    { call macro to send char to LPTNo.  If bit 4, the Printer Selected bit }
    { is not set upon return, it is assumed that an error has occurred.     }

  BEGIN
    ErrorCode := DoInt17(Ch, LPTNo);
    IF (ErrorCode AND $10) = $10 THEN { if bit 4 is set }
      ErrorCode := 0              { no error }
      { if bit 4 is not set, error is passed untouched and placed in IOResult }
  END;

  {$F+}                           { <==The following routines MUST be compiler as FAR }

  FUNCTION LstIgnore(VAR F : textrec) : Integer;
    { A do nothing, no error routine }
  BEGIN
    LstIgnore := 0                { return 0 for IOResult }
  END;

  FUNCTION LstOutput(VAR F : textrec) : Integer;
    { Send whatever has accumulated in the Buffer to int 17h   }
    { If error occurs, return in IOResult.  See Inside Turbo   }
    { Pascal chapter of TP4 manual for more info on TFDD       }
  TYPE TLine = String;
  LABEL Done;
  VAR
    i : Word;
    ErrorCode, J, EndChar : Integer;
    Line : TLine;

  BEGIN
    LstOutput := 0;
    ErrorCode := 0;
    WITH F DO BEGIN
      Line := Copy(BufPtr^, 0, BufPos);
      IF ((Ord(Line[1]) = 32) AND (Ord(Line[2]) = 13) AND (Ord(Line[3]) = 10))
      THEN WriteLn
      ELSE Write(Line);
      IF NOT Scripting THEN GOTO Done;
      FOR i := 0 TO Pred(BufPos) DO BEGIN
        Out_Char(BufPtr^[i], LPTNo, ErrorCode); { send each char to printer }
        IF ErrorCode <> 0 THEN BEGIN { if error }
          LstOutput := ErrorCode; { return errorcode in IOResult }
          GOTO Done;              { return from function }
        END
      END;
Done: BufPos := 0
    END;
  END;

  {$F-}                           { Near ok now }

  PROCEDURE AssignLst(VAR F : Text; LPTNumber : Word);
    { like Turbo's assign, except associates Text variable with one of the LPTs }
  BEGIN
    WITH textrec(F) DO BEGIN
      Mode := fmClosed;
      BufSize := SizeOf(Buffer);
      BufPtr := @Buffer;
      OpenFunc := @LstIgnore;     { you don't open the BIOS printer functions }
      CloseFunc := @LstIgnore;    { nor do you close them }
      InOutFunc := @LstOutput;    { but you can Write to them }
      FlushFunc := @LstOutput;    { and you can WriteLn to them }
      LPTNo := LPTNumber;         { user selected printer num (in [0..2]) }
      Move(LPTNames[LPTNumber], name, 4); { set name of device }
      BufPos := 0;                { reset BufPos }
    END;
  END;


  PROCEDURE LittleWindow;

  BEGIN
    WINDOW(1, 2, 80, 25);         {everything, but top line}
  END;


  PROCEDURE BigWindow;

  BEGIN
    WINDOW(1, 1, 80, 25);         {entire screen}
  END;



  {$I DECLARE.PA4 }

  {$I GENTOOLS.PA4 }

  {$I SPCTOOLS.PA4 }

  {$I DESCRIBE.PA4 }

END.
